package org.admanager.soa.plugin.popup.actions;

import java.util.Iterator;

import org.admanager.soa.plugin.Activator;
import org.admanager.soa.plugin.util.KermetaRunner;
import org.admanager.soa.plugin.util.ValidationDetailDialog;
import org.admanager.soadmanagement.plugin.soadmanagement.ComponentMapping;
import org.admanager.soadmanagement.plugin.soadmanagement.ComponentReferenceMapping;
import org.admanager.soadmanagement.plugin.soadmanagement.ComponentServiceMapping;
import org.admanager.soadmanagement.plugin.soadmanagement.CompositeMapping;
import org.admanager.soadmanagement.plugin.soadmanagement.ReferenceMapping;
import org.admanager.soadmanagement.plugin.soadmanagement.RootMapping;
import org.admanager.soadmanagement.plugin.soadmanagement.ServiceMapping;
import org.admanager.soadmanagement.plugin.soadmanagement.util.soadmanagementSwitch;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IFolder;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.MultiStatus;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.Status;
import org.eclipse.emf.common.util.Diagnostic;
import org.eclipse.emf.common.util.TreeIterator;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EPackage;
import org.eclipse.emf.ecore.EValidator;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.resource.ResourceSet;
import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl;
import org.eclipse.emf.ecore.util.Diagnostician;
import org.eclipse.emf.ecore.util.EcoreUtil;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.dialogs.Dialog;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.ocl.examples.xtext.oclinecore.validation.OCLinEcoreEObjectValidator;
import org.eclipse.ui.IObjectActionDelegate;
import org.eclipse.ui.IWorkbenchPart;

import fr.irisa.triskell.eclipse.console.EclipseConsole;
import fr.irisa.triskell.eclipse.console.IOConsole;

public class PatternViewExtractionActionDelegate implements
		IObjectActionDelegate {
	private ISelection selection;
	IWorkbenchPart targetPart;
	MultiStatus info;
	public PatternViewExtractionActionDelegate() {
		// TODO Auto-generated constructor stub
	}

	@Override
	public void run(IAction action) {
		// TODO Auto-generated method stub
		if (selection instanceof IStructuredSelection) {
			Iterator iter = ((IStructuredSelection) selection).iterator();
			while (iter.hasNext()) {
				Object obj = (Object) iter.next();
				if (obj instanceof IFile)
				{
					//Get file
					IFile inputModelFile = (IFile)obj;
					URI inputModel = URI.createURI(inputModelFile.getLocationURI().toString());
					//Get the current project
					IProject myProject = inputModelFile.getProject();

					//Get the URI for the output model
					IFolder patternViewFolder = myProject.getFolder("PatternView");
					if (!patternViewFolder.exists())
						try {
							patternViewFolder.create(true, true, new NullProgressMonitor());
						} catch (CoreException e1) {
							// TODO Auto-generated catch block
							e1.printStackTrace();
						}
					/*
					IFolder patternFolder = patternViewFolder.getFolder(inputModelFile.getName().replace("soapattern", ""));
					if (!patternFolder.exists())
						try {
							patternFolder.create(true, true, new NullProgressMonitor());
						} catch (CoreException e1) {
							// TODO Auto-generated catch block
							e1.printStackTrace();
						}
			        */
					
					EValidator.Registry.INSTANCE.put(null, new OCLinEcoreEObjectValidator());
					
					String strSOAMsg = "Pattern validation errors occured in the mapping model "
							+ inputModelFile.getName();
					info = new MultiStatus(Activator.PLUGIN_ID, 1, strSOAMsg, null);
					
					ResourceSet rs1 = new ResourceSetImpl();
					Resource r1 = rs1.getResource(inputModel, true);
					EObject eObject1 = r1.getContents().get(0);
					Diagnostic dia = Diagnostician.INSTANCE
							.validate(eObject1);
					if (dia.getSeverity() == Diagnostic.ERROR
							|| dia.getSeverity() == Diagnostic.WARNING) {
						EClass eClass = eObject1.eClass();
						EPackage ePackage = eClass.getEPackage();
						String strMsg = "The SCA model has been changed which causes validation errors occurred for the mapping model "
								+ inputModel.lastSegment().replace(".mapping", "")
								+ " at the pattern view "
								+ inputModelFile.getName();
						MultiStatus stsInfo = this.getStatus(dia, strMsg);
						info.add(stsInfo);
					}
					
					//EValidator.Registry.INSTANCE.put(null, new
					//		OCLinEcoreEObjectValidator());
					
					ValidationDetailDialog dialog;
					if (info.getChildren().length > 0)
					{
						dialog = new ValidationDetailDialog(targetPart.getSite().getShell(), "Validation result", Dialog.getImage(Dialog.DLG_IMG_ERROR), "Errors occurred during validation", info, Activator.getDefault());
						dialog.open();
					}		
					else
					{
						String metaPatternName = getPatternModelURI(inputModelFile).lastSegment().replace(".soapattern","");
						URI metaPatternModel = URI.createURI(patternViewFolder.getLocationURI()
								+ "/" + metaPatternName + "/"
								+ inputModel.lastSegment().replace("mapping",
										"ecore"));
						URI outputModel = URI.createURI(patternViewFolder.getLocationURI()
									+ "/" + metaPatternName + "/"
									+ inputModel.lastSegment().replace("mapping",
											"patternview"));
						//Unregister pattern view package
						EPackage.Registry.INSTANCE.remove("http://patternview/1.0");
						
						//Register pattern view package
						ResourceSet rs = new ResourceSetImpl();
						Resource r = rs.getResource(URI.createURI(metaPatternModel.toString()), true);
						EObject eObject = r.getContents().get(0);
						if (eObject instanceof EPackage) {
						    EPackage p = (EPackage)eObject;
						    EPackage.Registry.INSTANCE.put(p.getNsURI(), p);
						}
						
						//Run Kermeta
						IOConsole console = new EclipseConsole("Kermeta Simulator");
						try {						
							String sourcePatternUrl = inputModel.toString();
							String metaPatternUrl = metaPatternModel.toString();
							String targetPatternUrl = outputModel.toString();
							
							KermetaRunner.Mapping2View(sourcePatternUrl, metaPatternUrl, targetPatternUrl, console);
							
						} catch (Throwable e) {
							
							e.printStackTrace();
						}
						//End Run Kermeta
					}
					try {
						myProject.refreshLocal(IResource.DEPTH_INFINITE, new NullProgressMonitor() );
					} catch (CoreException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
				}
			}
		}
	}

	@Override
	public void selectionChanged(IAction action, ISelection selection) {
		// TODO Auto-generated method stub
		this.selection = selection;
		action.setEnabled(!selection.isEmpty());
	}

	@Override
	public void setActivePart(IAction action, IWorkbenchPart targetPart) {
		// TODO Auto-generated method stub
		this.targetPart = targetPart;
	}
	
	/**
	 * 
	 * @param mappingFile
	 * @return the corresponding pattern model of a mapping
	 */
	URI getPatternModelURI(IFile mappingFile) {
		// Obtain a new resource set
		ResourceSet resSet = new ResourceSetImpl();
		// Get the resource
		Resource resource = resSet.getResource(
				URI.createURI(mappingFile.getLocationURI().toString()), true);

		//MappingSwitch is used to get the right mapping type according to an object
		soadmanagementSwitch visitor = new soadmanagementSwitch() {
			public URI casePatternMapping(RootMapping object) {
				return null;
			}

			public URI caseCompositeMapping(CompositeMapping object) {
				URI uriPattern = object.getTarget().eResource().getURI();
				return uriPattern;
			}

			public URI caseComponentMapping(ComponentMapping object) {
				URI uriPattern = object.getTarget().eResource().getURI();
				return uriPattern;
			}

			public URI caseReferenceMapping(ReferenceMapping object) {
				URI uriPattern = object.getTarget().eResource().getURI();
				return uriPattern;
			}

			public URI caseServiceMapping(ServiceMapping object) {
				URI uriPattern = object.getTarget().eResource().getURI();
				return uriPattern;
			}

			public URI caseComponentReferenceMapping(
					ComponentReferenceMapping object) {
				URI uriPattern = object.getTarget().eResource().getURI();
				return uriPattern;
			}

			public URI caseComponentServiceMapping(
					ComponentServiceMapping object) {
				URI uriPattern = object.getTarget().eResource().getURI();
				return uriPattern;
			}

			@Override
			public URI defaultCase(EObject object) {
				return null;
			}
		};

		URI uriPattern = null;
		//Search through the mapping tree, find at least one target general pattern model URI
		for (TreeIterator<Object> iter = EcoreUtil.getAllContents(resource,
				true); iter.hasNext();) {
			EObject eObject = (EObject) iter.next();
			uriPattern = (URI)visitor.doSwitch(eObject);
			if (uriPattern != null)
				break;
		}
		return uriPattern;
	}

	/**
	 * 
	 * @param dia
	 * @param strMsg
	 * @return The status from a diagnostic
	 */
	MultiStatus getStatus(Diagnostic dia, String strMsg) {
		// Walk through all the sub diagnostics and document their messages in
		// the status
		MultiStatus subMultiStatus = new MultiStatus(Activator.PLUGIN_ID, 1,
				strMsg, null);
		;
		for (Iterator<Diagnostic> iterator = dia.getChildren().iterator(); iterator
				.hasNext();) {
			Diagnostic subDia = (Diagnostic) iterator.next();
			Status subStatus = new Status(IStatus.INFO, Activator.PLUGIN_ID, 1,
					subDia.getMessage(), null);
			subMultiStatus.add(subStatus);
		}
		return subMultiStatus;
	}
}
